#ifndef SWEGL_QUATERNION_H
#define SWEGL_QUATERNION_H

namespace swegl
{
	
class Quaternion
{
public:
	Quaternion();
	Quaternion(float x, float y, float z, float w);

	float operator[](uint index) const;
	float &operator[](uint index);
	
	Quaternion &operator += (const Quaternion &rhs);
	Quaternion &operator -= (const Quaternion &rhs);
	Quaternion &operator *= (float v);
	Quaternion &operator /= (float v);
	Quaternion operator + (const Quaternion &rhs) const;
	Quaternion operator - (const Quaternion &rhs) const;
	Quaternion operator * (float v) const;
	Quaternion operator / (float v) const;
	Quaternion operator - () const;

	bool operator == (const Quaternion &rhs) const;
	bool operator != (const Quaternion &rhs) const;
	bool isEqual(const Quaternion &rhs) const;
	bool isEqual(const Quaternion &rhs, float epsilon) const;
	
	Matrix3x3 toMatrix3x3() const;

	// cast operator
	const float *toPtr() const;
	float *toPtr();


	float x, y, z, w;
};

inline Quaternion::Quaternion()
{
}

inline Quaternion::Quaternion(float x, float y, float z, float w) : x(x), y(y), z(z), w(w)
{
}

inline float Quaternion::operator [] (uint index) const
{
	return (&x)[index];
}
	
inline float &Quaternion::operator [] (uint index)
{
	return (&x)[index];
}

inline bool Quaternion::operator == (const Quaternion &rhs) const
{
	return x == rhs.x && y == rhs.y && z == rhs.z && w == rhs.w;
}

inline bool Quaternion::operator != (const Quaternion &rhs) const
{
	return x != rhs.x || y != rhs.y || z != rhs.z || w != rhs.w;
}

inline bool Quaternion::isEqual(const Quaternion &rhs) const
{
	return x == rhs.x && y == rhs.y && z == rhs.z && w == rhs.w;
}

inline bool Quaternion::isEqual(const Quaternion &rhs, float epsilon) const
{
	return x >= rhs.x - epsilon && x <= rhs.x + epsilon
		&& y >= rhs.y - epsilon && y <= rhs.y + epsilon
		&& z >= rhs.z - epsilon && z <= rhs.z + epsilon
	    && w >= rhs.w - epsilon && w <= rhs.w + epsilon;
}

inline const float *Quaternion::toPtr() const
{
	return &x;
}

inline float *Quaternion::toPtr()
{
	return &x;
}

}

#endif
